package com.jiao.service.impl;

import com.jiao.constants.Constants;
import com.jiao.domain.DTO.CommentDto;
import com.jiao.domain.LoginUser;
import com.jiao.domain.Result;
import com.jiao.domain.VO.CommentVo;
import com.jiao.domain.VO.PageVo;
import com.jiao.domain.entity.Comment;
import com.jiao.domain.entity.SysUser;
import com.jiao.enums.ExceptionCodeEnum;
import com.jiao.mapper.CommentMapper;
import com.jiao.mapper.SysUserMapper;
import com.jiao.service.CommentService;
import com.jiao.utils.BeanCopyUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 评论表(Comment)表服务实现类
 *
 * @author makejava
 * @since 2022-02-28 10:31:14
 */
@Service("commentService")
@Slf4j
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {
    @Autowired
    SysUserMapper sysUserMapper;
    @Autowired
    CommentMapper commentMapper;
    /**
     * 参数 articleId:文章id, pageNum: 页码, pageSize: 每页条数
     * 此函数不包含子评论，只显示一级评论
     */
    @Override
    public Result<PageVo> commentList(Long articleId, Integer pageNum, Integer pageSize) {
        //1,获取一级评论的筛选条件：文章id = articleId ，根评论id = -1
        LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Comment::getRootId,-1L)
                .eq(Comment::getArticleId,articleId);
        //2,根据分页获取数据
        Page<Comment> page = new Page<>(pageNum,pageSize);
        page(page,queryWrapper);
        List<Comment> records = page.getRecords();
        //3,一次性从数据库中查取所需用户信息
        Set<Long> ids = new HashSet<>();
        records.forEach(comment -> {
            ids.add(comment.getCreateBy());
            if(comment.getRootId() == -1){
                ids.add(comment.getToCommentUserId());
            }
        });
        List<SysUser> sysUsers = sysUserMapper.selectBatchIds(ids);
        // 4,把List转成Map
//        Map<Long, SysUser> userMap = new HashMap<>();
//        for (SysUser sysUser : sysUsers) {
//            userMap.put(sysUser.getId(), sysUser);
//        }
        Map<Long, SysUser> userMap = sysUsers.stream().collect(Collectors.toMap(SysUser::getId, sysUser -> sysUser));

        // 5,封装对象
        List<CommentVo> commentVos = BeanCopyUtils.copyBeanList(records, CommentVo.class);
        for (CommentVo commentVo : commentVos) {
            //存评论人名字
            SysUser user = userMap.get(commentVo.getCreateBy());
            commentVo.setUsername(user.getNickName());
            //存被评论人名字
            if(commentVo.getToCommentUserId() != -1){
                user = userMap.get(commentVo.getToCommentUserId());
                commentVo.setToCommentUserName(user.getNickName());
            }
        }
        PageVo pageVo = new PageVo(commentVos,page.getTotal());
        return Result.success(pageVo);
    }

    /*
    * 获取文章id下面的所有评论
    * 分页其实就是限制查找数据量，最终限制的是根节点，而查找子节点数据，其实是为了完善根节点数据。
    * * */
    public Result<PageVo> AllCommentList(Long articleId, Integer pageNum, Integer pageSize) {
        // 1，获取文章下所需分页的根评论
        LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Comment::getArticleId,articleId);
        queryWrapper.eq(Comment::getRootId,-1L);
        Page<Comment> page = new Page<>(pageNum,pageSize);
        page(page,queryWrapper);
        List<Comment> rootRecords = page.getRecords();
        // 2,根评论的下面的所有子评论
        if(rootRecords.isEmpty()){
            return Result.success( new PageVo());
        }
        List<Long> rootIds = rootRecords.stream().map(Comment::getId).collect(Collectors.toList());
        log.info("rootIds:{}",rootIds);
        List<Comment> childrenComments = new ArrayList<>();
        if(!rootIds.isEmpty()){
            LambdaQueryWrapper<Comment> queryWrapper1 = new LambdaQueryWrapper<>();
            queryWrapper1.in(Comment::getRootId,rootIds);
            childrenComments = commentMapper.selectList(queryWrapper1);
        }
        // 3,一次性从数据库中查取所需用户信息
        Set<Long> allIds = new HashSet<>();
        childrenComments.forEach(comment -> {
            allIds.add(comment.getCreateBy());
            allIds.add(comment.getToCommentUserId());
        });
        rootRecords.forEach(comment -> allIds.add(comment.getCreateBy()));
        List<SysUser> sysUsers = sysUserMapper.selectBatchIds(allIds);

        // 4,用户数据list转map
        Map<Long, SysUser> userMap = sysUsers.stream().collect(Collectors.toMap(SysUser::getId, sysUser -> sysUser));
        // 5,封装根节点数据
        List<CommentVo> commentVoList = BeanCopyUtils.copyBeanList(rootRecords, CommentVo.class);
        Map<Long, CommentVo> rootCommentMap = commentVoList.stream().collect(Collectors.toMap(CommentVo::getId, commentVo -> {
            commentVo.setUsername( //使用Optional去包裹有可能为空的对象
                    Optional.ofNullable(userMap.get(commentVo.getCreateBy()))
                            .map(SysUser::getNickName) //然后在map方法内进行对象操作
                            .orElse(""));//这样最后使用orElse方法进行兜底，如果进行的操作中有空异常，则返回orElse方法中封装的对应信息去代替异常。
            commentVo.setChildren(new ArrayList<>());
            return commentVo; }
        ));
        // 6,像根节点传入子节点数据集
        childrenComments.forEach(Comment -> {
            CommentVo commentVo = BeanCopyUtils.copyBean(Comment, CommentVo.class);
            commentVo.setUsername(userMap.get(Comment.getCreateBy()).getNickName());
            commentVo.setToCommentUserName(userMap.get(Comment.getToCommentUserId()).getNickName());
            // rootCommentMap.get(commentVo.getRootId()).getChildren().add(commentVo);
            Optional.ofNullable(rootCommentMap.get(commentVo.getRootId()))
                    .map(CommentVo::getChildren)
                    .map(children -> children.add(commentVo))
                    .orElseGet(()->{ return null;});
        });

        List<CommentVo> CommentVos = new ArrayList<>(rootCommentMap.values());
        PageVo pageVo = new PageVo(CommentVos,page.getTotal());
        return Result.success(pageVo);
    }

    @Override
    public Result<String> insertCommentt(CommentDto commentDto) {
        LoginUser loginUser = (LoginUser)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        SysUser sysUser = loginUser.getSysUser();
        Comment comment = BeanCopyUtils.copyBean(commentDto, Comment.class);
        comment.setCreateBy(sysUser.getId());
        comment.setUpdateBy(sysUser.getId());
        if(commentMapper.insert(comment) == Constants.STATUS_NORMAL){
            return Result.success();
        }else {
            return Result.error(ExceptionCodeEnum.SYSTEM_ERROR);
        }
    }
}
